package cn.finder.httpcommons;

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import cn.finder.httpcommons.domain.Message;
import cn.finder.httpcommons.parser.IParser;
import cn.finder.httpcommons.parser.JsonParser;
import cn.finder.httpcommons.parser.XmlParser;
import cn.finder.httpcommons.request.BaseRequest;
import cn.finder.httpcommons.request.IUploadRequest;
import cn.finder.httpcommons.request.JsonStringRequest;
import cn.finder.httpcommons.request.StreamRequest;
import cn.finder.httpcommons.request.StringDataRequest;
import cn.finder.httpcommons.response.ApiResponse;
import cn.finder.httpcommons.utils.ApiUtils;
import cn.finder.httpcommons.utils.FileItem;
import cn.finder.httpcommons.utils.JsonUtils;
import cn.finder.httpcommons.utils.WebUtils;

/***
 * 直接发送 数据
 * @author whl
 *
 */
public class HttpsPostClient implements IClient {

	public final String APP_KEY = "app_key";
 
    /// <summary>
    /// 是否启用对返回字符串进行解析 XML或者JSON ，如果为false，那么不解析 直接使用原始数据
    /// </summary>
    private boolean disableParser;
    private boolean disableTrace;
    /// <summary>
    /// 返回数据格式
    /// </summary>
    private String format;



    public final String FORMAT = "format";
    public final String FORMAT_XML = "xml";
    public final String FORMAT_JSON = "json";
    private String url;
    
    private Map<String, String> systemParameters;
   // public final String TIMESTAMP = "timestamp";
    private ILogger apiLogger;
    
    private WebUtils webUtils;


    /// <summary>
    /// 默认客户端 
    /// </summary>
    /// <param name="serverUrl">服务器地址</param>
    /// <param name="appKey">应用KEY</param>
    /// <param name="appSecret">应用秘钥</param>
    public HttpsPostClient(String url)
    {
        this.format = "json";
        this.url = url;
        this.webUtils = new cn.finder.httpcommons.utils.WebUtils();
        this.apiLogger = new DefaultLogger();
    }
    /// <summary>
    ///  默认客户端 
    /// </summary>
    /// <param name="serverUrl">服务器地址</param>
    /// <param name="appKey">应用KEY</param>
    /// <param name="appSecret">应用秘钥</param>
    /// <param name="format">返回数据格式</param>
    public HttpsPostClient(String serverUrl, String format)
        
    {
    	this(serverUrl);
        this.format = format;
    }
    public HttpsPostClient(String serverUrl, String format,boolean disableParser)
    {
    	this(serverUrl);
        this.format = format;
        this.disableParser = disableParser;
    }

    /// <summary>
    /// 创建错误消息到ApsResponse对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="errCode"></param>
    /// <param name="errMsg"></param>
    /// <returns></returns>
    private  <T extends ApiResponse>  T createErrorResponse(String errCode, String errMsg)
    {
    	
        @SuppressWarnings("unchecked")
		T local=null;
       
        local.getMessage().setStatusCode(Message.StatusCode_ClientError);
        local.getMessage().setMsg(errMsg);
        if (FORMAT_XML.equals(this.format))
        {
           /* XmlDocument document = new XmlDocument();
            XmlElement newChild = document.CreateElement("error_response");

            XmlElement eleMessage = document.CreateElement("message");

            XmlElement elementCode = document.CreateElement("statusCode");
            elementCode.InnerText = errCode;
            eleMessage.AppendChild(elementCode);

            XmlElement elementMsg = document.CreateElement("msg");
            elementMsg.InnerText = errMsg;
            eleMessage.AppendChild(elementMsg);

            XmlElement elementDetail = document.CreateElement("detail");
            elementMsg.InnerText = errMsg;
            eleMessage.AppendChild(elementDetail);


            document.AppendChild(eleMessage);
            local.Body = document.OuterXml;*/
            return local;
        }
        Map<String, Object> messageDict = new HashMap<String, Object>();

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("statusCode", errCode);
        map.put("msg", errMsg);

        messageDict.put("message", map);


        Map<String, Object> error_response_dict = new HashMap<String, Object>();
        error_response_dict.put("error_response", messageDict);

        //updatedragon
        /*JSONObject jobj =  JSONObject.fromObject(error_response_dict);
        
        local.setBody(jobj.toString());*/
        String s= JsonUtils.objToJsonString(error_response_dict);
        local.setBody(s);
        return local;
    }



    @SuppressWarnings("unchecked")
	private  <T extends ApiResponse>  T doExecute(BaseRequest<T> request, String session, Date timestamp)
    {
    	T resp;
        try
        {
            //请求参数验证
            request.validate();
        }
        catch (Exception exception)
        {
            return this.createErrorResponse(Message.StatusCode_ClientError+"", exception.toString());
        }
        Map<String,String> reqParams = request.parameters();
        ApiDictionary parameters = new ApiDictionary((HashMap<String,String>)reqParams);


        // 从 Assembly中获取 版本信息
        String versionStr = Version.VERSION_1_0;

        
        
        //String strGetUrl = this.webUtils.buildGetUrl(this.url, parameters);
        String strGetUrl = this.webUtils.buildGetUrl(this.url,null);
        strGetUrl+="其他数据post发送";
        //String dataJsonstr = JsonUtils.getJsonString4JavaPOJO(reqParams);
        
        try
        {
            T respTmp = null;
            String retStr;

            if (request instanceof IUploadRequest<?>)
            {//  二进制(文件、图片)请求
                Map<String, FileItem> fileParams = ApiUtils.CleanupDictionary(((IUploadRequest<T>)request).fileParameters());
                if (fileParams != null && fileParams.size() > 0)
                {

                }

                //retStr = this.webUtils.doPost(this.url, parameters, fileParams);
                retStr = this.webUtils.doPostMultipartHttps(this.url, parameters, fileParams);
            }
            else if (request instanceof StreamRequest<?>)
            {
                retStr = this.webUtils.buildGetUrl(this.url, parameters);
                this.disableParser=true;//流类型 默认的为true;
            }
            else if(request instanceof StringDataRequest<?>){
            	StringDataRequest<T> strDataReq = (StringDataRequest<T>)request;
            //	System.out.println("=====strDataReq:"+strDataReq.Data());
            	retStr = this.webUtils.doHttps(this.url, "POST",strDataReq.Data());
            	System.out.println("===请求返回数据:"+retStr);
            }
            else
            {
                //发送普通文本请求
                retStr = this.webUtils.doHttps(this.url, "POST",reqParams);
               // retStr = "{message:{statusCode:404,msg:\"调用失败，查看服务器是否开启或者网络是否连接\",detail:null},pageIndex:1,pageSize:10,totalRecord:0,pageCount:0,entities:[]}";
            }
            if (this.disableParser)
            {
            	
            	Object c = request.responseClassType().newInstance();
            	respTmp=(T)c;
            	
                respTmp.setBody(retStr);
            }
            else if (FORMAT_XML.equals(this.format))
            {
                IParser<T> parser = new XmlParser<T>();
                respTmp =  parser.parse(retStr,request.responseClassType());
            }
            else
            {
                IParser<T> parser = new JsonParser<T>();
                
               
                respTmp =  parser.parse(retStr,request.responseClassType());
            }
            if (!this.disableTrace && respTmp.getMessage().getStatusCode() != Message.StatusCode_OK)
            {
                this.apiLogger.warn(new StringBuffer(strGetUrl).append(" response error!\r\n").append(respTmp.getBody()).toString());
            }
            resp = respTmp;
        }
        catch (Exception exp)
        {
            if (!this.disableTrace)
            {
                this.apiLogger.error(new StringBuffer(strGetUrl).append(" request error!\r\n").append(exp.toString()).toString());
            }
            // throw exp;

            String respStrNotFound = "{message:{statusCode:404,msg:\"调用失败，查看服务器是否开启或者网络是否连接\",detail:null},pageIndex:1,pageSize:10,totalRecord:0,pageCount:0,entities:[]}";
            IParser<T> parser = new JsonParser<T>();
            resp = parser.parse(respStrNotFound,request.responseClassType());
            
        }
        //if(OnResponse!=null)
        //    OnResponse(resp);
       // finally
       // {
            return resp;
      //  }
    }

   


    /// <summary>
    /// 返回请求 字符串数据 只用作测试
    /// </summary>
    /// <param name="parameters"></param>
    /// <param name="session"></param>
    /// <param name="timestamp"></param>
    /// <returns></returns>
    public String execute(ApiDictionary parameters, String session, Date timestamp,String method) 
    {
    	//String jsonStr = JSONUtils.valueToString(parameters);

    	String jsonStr = JsonUtils.objToJsonString(parameters);
    	
        // 从 Assembly中获取 版本信息
        String versionStr = Version.VERSION_1_0;

        parameters.addAll(this.systemParameters);

        //参数签名   appSecret+参数+appSecret  暂时不需要 加快处理速度
        //parameters.Add(SIGN, ApiUtils.SignRequest(parameters, this.appSecret));




        // updated by dragon  20140609
        String dataJsonstr = jsonStr;
        parameters.add("data", dataJsonstr);

        String strGetUrl = this.webUtils.buildGetUrl(this.url, parameters);


        try
        {
            String retStr;
           
            if (true)
            {

                //发送普通文本请求
                retStr = this.webUtils.doPost(this.url, parameters);

         
            }
            return retStr;
           
        }
        catch (Exception exp)
        {
            if (!this.disableTrace)
            {
                this.apiLogger.error(new StringBuffer(strGetUrl).append(" request error!\r\n").append(exp.toString()).toString());
            }
            throw new RuntimeException(exp);
        }
      
    }



    /// <summary>
    /// 下载数据流
    /// </summary>
    /// <param name="parameters"></param>
    /// <param name="session"></param>
    /// <param name="timestamp"></param>
    /// <returns></returns>
    public String executeFileStream(ApiDictionary parameters, String session, Date timestamp, String method)
    {


    	//String jsonStr = JSONUtils.valueToString(parameters);

    	String jsonStr = JsonUtils.objToJsonString(parameters);

        // 从 Assembly中获取 版本信息
        String versionStr = Version.VERSION_1_0;



        parameters.addAll(this.systemParameters);

        //参数签名   appSecret+参数+appSecret  暂时不需要 加快处理速度
        //parameters.Add(SIGN, ApiUtils.SignRequest(parameters, this.appSecret));


        String strGetUrl = this.webUtils.buildGetUrl(this.url, parameters);


        try
        {
            String retStr;


            retStr = this.webUtils.buildGetUrl(this.url, parameters);


            return retStr;

        }
        catch (Exception exp)
        {
            if (!this.disableTrace)
            {
                this.apiLogger.error(new StringBuffer(strGetUrl).append(" request error!\r\n").append(exp.toString()).toString());
            }
            throw new RuntimeException(exp);
        }

    }



    /// <summary>
    /// 测试用的所有的通用请求 普通文本和文件上传
    /// </summary>
    /// <param name="parameters"></param>
    /// <param name="fileParams"></param>
    /// <param name="session"></param>
    /// <param name="timestamp"></param>
    /// <param name="method"></param>
    /// <returns></returns>
    public String execute(ApiDictionary parameters, Map<String, FileItem> fileParams, String session, Date timestamp, String method)
    {
        //生成JSON
        String jsonStr = "";

        if (fileParams != null && fileParams.size() > 0)
        {
           
        	
            Set<Entry<String,FileItem>> setEntry=fileParams.entrySet();
            
            Iterator<Entry<String,FileItem>> itr =  setEntry.iterator();
            
            while(itr.hasNext()){
            	
            	Entry<String,FileItem> entry  =  itr.next();
            	
            	String key = entry.getKey();
                FileItem value = entry.getValue();
                		
                parameters.add(key, value.getFileName());
            	
            }
            
            
        }
        else
        {
        	 jsonStr = JsonUtils.objToJsonString(parameters);
        }



        parameters.addAll(this.systemParameters);


        String strGetUrl = this.webUtils.buildGetUrl(this.url, parameters);


        try
        {
            String retStr;

            if (true)
            {

                //发送带文件请求
                retStr = this.webUtils.doPost(this.url, parameters, fileParams);
            
            }
            return retStr;

        }
        catch (Exception exp)
        {
            if (!this.disableTrace)
            {
                this.apiLogger.error(new StringBuffer(strGetUrl).append(" request error!\r\n").append(exp.toString()).toString());
            }
            throw new RuntimeException(exp);
        }
    }


    /// <summary>
    /// 构建 GET 请求数据
    /// </summary>
    /// <param name="parameters"></param>
    /// <param name="session"></param>
    /// <param name="timestamp"></param>
    /// <returns></returns>
    public String  buildReqGetUrlString(ApiDictionary parameters, String session, Date timestamp,String method) 
    {
        
        String strGetUrl = this.webUtils.buildGetUrl(this.url, parameters);
        return strGetUrl;
    }

   
   

    public  <T extends ApiResponse>  T execute(BaseRequest<T> request)
    {
        return this.execute(request, "");
    }

    public  <T extends ApiResponse>  T  execute(BaseRequest<T> request, String session)
    {
        return this.execute(request, session, new Date(System.currentTimeMillis()));
    }

    public  <T extends ApiResponse>  T execute(BaseRequest<T> request, String session, Date timestamp)
    {
        return this.doExecute(request, session, timestamp);
       
    }



    public void SetDisableParser(boolean disableParser)
    {
        this.disableParser = disableParser;
    }

    public void SetDisableTrace(boolean disableTrace)
    {
        this.disableTrace = disableTrace;
    }

    public void SetSystemParameters(Map<String, String> systemParameters)
    {
        this.systemParameters = systemParameters;
    }

    public void SetTimeout(int timeout)
    {
        this.webUtils.setTimeout(timeout);
    }

    public void SetApsLogger(ILogger apsLogger)
    {
        this.apiLogger = apsLogger;
    }


}
